package mysql

import (
	"io"
	"text/template"

	"gitee.com/lipore/plume/db_gorm/gen/code"
	"gitee.com/lipore/plume/db_gorm/gen/spec"
)

type RepositoryGenerator struct {
	EntityModel             code.Struct
	RepositoryType          code.Type
	RepositoryInterfaceType code.ExternalType
}

func NewRepositoryGenerator(entityModel code.Struct, repositoryType code.ExternalType) *RepositoryGenerator {
	return &RepositoryGenerator{
		EntityModel:             entityModel,
		RepositoryType:          code.SimpleType(repositoryType.Name),
		RepositoryInterfaceType: repositoryType,
	}
}

func (repoGen *RepositoryGenerator) GenerateConstructor(buffer io.Writer) error {
	tmpl, err := template.New("file_base").Parse(constructorTemplate)
	if err != nil {
		return err
	}

	tmplData := constructorData{
		RepositoryName: repoGen.RepositoryType.Code(),
		RepositoryType: repoGen.RepositoryInterfaceType.Code(),
	}

	if err := tmpl.Execute(buffer, tmplData); err != nil {
		return err
	}

	return nil
}

func (repoGen *RepositoryGenerator) GenerateMethod(methodSpec spec.MethodSpec, buffer io.Writer) error {
	switch operation := methodSpec.Operation.(type) {
	case spec.InsertOperation:
		return renderCreateMethod(methodSpec, repoGen.EntityModel.ReferencedType(), repoGen.RepositoryType, operation, buffer)
	case spec.DeleteOperation:
		return renderDeleteMethod(methodSpec, repoGen.EntityModel.ReferencedType(), repoGen.RepositoryType, operation, buffer)
	case spec.UpdateOperation:
		return renderUpdateMethod(methodSpec, repoGen.EntityModel.ReferencedType(), repoGen.RepositoryType, operation, buffer)
	case spec.FindOperation:
		return renderFindMethod(methodSpec, repoGen.EntityModel.ReferencedType(), repoGen.RepositoryType, operation, buffer)
	case spec.CountOperation:
		return renderCountMethod(methodSpec, repoGen.EntityModel.ReferencedType(), repoGen.RepositoryType, operation, buffer)
	}
	return nil
}
